package schedule;

import java.util.ArrayList;

import plan.Plan;
import start.Start;
import auftrag.Auftrag;
import auftrag.Produkt;
import auftrag.Ressource;

public class IterateVariants implements ISchedule {
	private long lMaxTime = 10000;
	double t = 10;
	int id = 0;
	
	@Override
	public Plan makePlan(ArrayList<?> pAuftragList,
			ArrayList<Ressource> pRessourceList) {
		//Sortiere die Aufträge nach EDF, dann nach Priorität
		Plan p = new Plan();
		ArrayList<Produkt> prodList = new ArrayList<Produkt>();
		if(Auftrag.class.isInstance(pAuftragList.get(0))){
			ArrayList<Auftrag> arrAuftrag = new ArrayList<Auftrag>();
			for(Object o : pAuftragList)
				arrAuftrag.add((Auftrag)o);
			for(Auftrag a : arrAuftrag){
				prodList.addAll(a.getAuftragProdukte());
			}
		} else if(Produkt.class.isInstance(pAuftragList.get(0))){
			for(Object o : pAuftragList){
				prodList.add((Produkt)o);
			}
		}
		//SimplePlan fügt einfach eine Produktliste mit gewählten Varianten der Reihe nach in die Maschinen ein
		for(Ressource r : pRessourceList)
			r.clear();
		p = new SimplePlan().makePlan(prodList, pRessourceList);
		System.out.println("Intial plan's Quality: "+p.getQuality(false)+"\tt:"+t);
		int it = 0;
		int quality, nCountNothingChanged = 0;
		long lStart = System.currentTimeMillis();
		//solange die Qualität nicht 0 ist und t > 0.1
		while(System.currentTimeMillis()-lStart < lMaxTime && p.getQuality(false) > 0 && nCountNothingChanged < 500){
			Start.it++;
			Plan pNeighbour;
			//alte Qualität
			quality = p.getQuality(false);

			
			ArrayList<Auftrag> belated = new ArrayList<Auftrag>();
			for(Produkt tempP : prodList){
				int penalty = tempP.getParent().getEndDate()*tempP.getParent().getPriority();
				if(penalty > 0 && !belated.contains(tempP.getParent())){
					belated.add(tempP.getParent());
				}
			}
			
			int nA = (int) (Math.random()*belated.size());
			Auftrag a = belated.get(nA);
			
			//bestimme alte Variante für Rollback
			int oldVariant = a.getAuftragProdukte().get(0).getProduktVariante().indexOf(a.getAuftragProdukte().get(0).getChosenVariante());
			
			//wähle neue Variante
			for(Produkt prodTemp : a.getAuftragProdukte())
				prodTemp.chooseVariant(oldVariant+1, 0);
			
			for(Ressource r : pRessourceList)
				r.clear();
			
			//neuer Plan
			pNeighbour = new SimplePlan().makePlan(prodList, pRessourceList);
			
			//falls neuer Plan besser: behalten
			if(pNeighbour.getQuality(true) < quality + t){
				p = pNeighbour;
				nCountNothingChanged = 0;
				
				if(p.getQuality(false) < quality)
					System.out.println((System.currentTimeMillis()-lStart)+" IV: Quality:"+p.getQuality(false)+"\tt:"+t);
			//sonst: Rollback, t verkleinern
			} else {
				for(Produkt prodTemp : a.getAuftragProdukte())	
					prodTemp.chooseVariant(oldVariant, 0);
				
				nCountNothingChanged++;
				if(nCountNothingChanged > 0 && nCountNothingChanged % 5 == 0)
					t=t*0.9;
				if(t < 0.1)
					t = 0;
				
				for(Ressource r : pRessourceList)
					r.clear();
			}
		}
		for(Ressource r : pRessourceList)
			r.clear();
		
		p = new SimplePlan().makePlan(prodList, pRessourceList);
		System.err.println("IV Iterations: "+it);
		return p;
	}
	
	public void setMaxTime(long t){
		lMaxTime = t;
	}
	
	public void setId(int id){
		this.id = id;
	}
	
	public void setTemperature(double t){
		this.t = t;
	}
}
